export interface IVideoOptions {
  src: string
  muted: boolean
  defaultMuted?: boolean
  preload: boolean
  volume: number
  playbackRate: number
}

export class VideoBase {
  private $el?: HTMLVideoElement // 视频dom对象
  private _loading: boolean = false // 是否正在加载
  private _duration: number = 0 // 视频总秒数
  private _width: number = 0 // 视频宽度
  private _height: number = 0 // 视频高度
  private _bufferedTime: number = 0 // 已缓冲的秒数
  private _currentTime: number = 0 // 已播放的秒数
  private _snapshoot: string = '' // 视频快照
  private _isFullScreen: boolean = false
  private _showSnapshoot: boolean = false

  // 已缓冲百分比
  get bufferValue(): number {
    const value: number = this._bufferedTime / this._duration * 100
    return parseFloat(value.toFixed(2) || '0')
  }

  // 是否正在加载
  get loading() {
    return this._loading
  }

  // 是否全屏显示
  get isFullScreen() {
    return this._isFullScreen
  }

  // ==================视频dom相关事件===============
  private abort() {
    this._loading = true
    this.getBuffered()
  }

  private canplay() {
    this.getBuffered()
  }

  private ended() {
    this._loading = false
  }

  private error() {
    this._loading = false
  }

  private loadeddata() {
    this._loading = false
    this.getBuffered()
  }

  private loadedmetadata({ target }: Event) {
    this._loading = false
    this._width = (target as HTMLVideoElement).videoWidth
    this._height = (target as HTMLVideoElement).videoHeight
    this.getBuffered()
  }

  private loadstart() {
    this.getBuffered()
    if (this.bufferValue < 100 && this._currentTime >= this._bufferedTime) {
      this._loading = true
    }
  }

  private pause() {

  }

  private playing() {
    this._loading = false
    this.getBuffered()
  }

  private progress() {
    this.getBuffered()
  }

  private seeked() {
    this.getSnapshoot()
    this.getBuffered()
  }

  private stalled() {
    this.getBuffered()
    if (this.bufferValue < 100 && this._currentTime >= this._bufferedTime) {
      this._loading = true
    }
  }

  private suspend() {
    this.getBuffered()
  }

  private timeupdate({ target }: Event) {
    const currentTime = (target as HTMLVideoElement).currentTime
    this._currentTime = currentTime
    this.getBuffered()
  }

  private waiting() {
    this._loading = true
    this.getBuffered()
  }

  private fullscreenchange(e: any) {
    const video = e.target
    this._isFullScreen = video.webkitDisplayingFullscreen
  }

  // ==========================================================

  // 添加事件监听
  private addEventListeners() {
    if (!this.$el) return
    // 视频的加载已放弃
    this.$el.removeEventListener('abort', this.abort)
    this.$el.addEventListener('abort', this.abort)

    // 浏览器可以播放视频
    this.$el.removeEventListener('canplay', this.canplay)
    this.$el.addEventListener('canplay', this.canplay)

    // 目前的播放列表已结束
    this.$el.removeEventListener('ended', this.ended)
    this.$el.addEventListener('ended', this.ended)

    // 视频加载期间发生错误
    this.$el.removeEventListener('error', this.error)
    this.$el.addEventListener('error', this.error)

    // 浏览器已加载视频的当前帧
    this.$el.removeEventListener('loadeddata', this.loadeddata)
    this.$el.addEventListener('loadeddata', this.loadeddata)

    // 浏览器已加载视频的元数据
    this.$el.removeEventListener('loadedmetadata', this.loadedmetadata)
    this.$el.addEventListener('loadedmetadata', this.loadedmetadata)

    // 浏览器开始查找视频
    this.$el.removeEventListener('loadstart', this.loadstart)
    this.$el.addEventListener('loadstart', this.loadstart)

    // 视频已暂停
    this.$el.removeEventListener('pause', this.pause)
    this.$el.addEventListener('pause', this.pause)

    // 视频在已因缓冲而暂停或停止后已就绪
    this.$el.removeEventListener('playing', this.playing)
    this.$el.addEventListener('playing', this.playing)

    // 浏览器正在下载视频
    this.$el.removeEventListener('progress', this.progress)
    this.$el.addEventListener('progress', this.progress)

    // 用户已移动/跳跃到视频中的新位置
    this.$el.removeEventListener('seeked', this.seeked)
    this.$el.addEventListener('seeked', this.seeked)

    // 浏览器尝试获取媒体数据，但数据不可用
    this.$el.removeEventListener('stalled', this.stalled)
    this.$el.addEventListener('stalled', this.stalled)

    // 浏览器刻意不获取媒体数据
    this.$el.removeEventListener('suspend', this.suspend)
    this.$el.addEventListener('suspend', this.suspend)

    // 当目前的播放位置已更改时
    this.$el.removeEventListener('timeupdate', this.timeupdate)
    this.$el.addEventListener('timeupdate', this.timeupdate)

    // 视频由于需要缓冲下一帧而停止
    this.$el.removeEventListener('waiting', this.waiting)
    this.$el.addEventListener('waiting', this.waiting)

    // 视频全屏切换触发
    this.$el.removeEventListener('fullscreenchange', this.fullscreenchange)
    this.$el.addEventListener('fullscreenchange', this.fullscreenchange)
  }

  // 获取缓冲信息
  private getBuffered() {
    if (!this.$el) return
    this._duration = this.$el.duration || this._duration
    if (this.$el.buffered && this.$el.buffered.length !== 0) {
      try {
        this._bufferedTime = this.$el.buffered.end(this.$el.buffered.length - 1)
      } catch (e) {}
    }
  }

  // 获取视频快照
  public getSnapshoot() {
    if (!this.$el) return Promise.resolve(this._snapshoot)
    const video = this.$el
    // 创建画布
    const canvas = document.createElement('canvas')
    // 获取画布上下文
    const context = canvas.getContext('2d') as CanvasRenderingContext2D
    // 设置画布的宽和高
    canvas.width = this._width
    canvas.height = this._height
    context.fillRect(0, 0, this._width, this._height)
    context.drawImage(video, 0, 0, this._width, this._height)
    const dataUrl = canvas.toDataURL('image/jpeg')
    this._snapshoot = dataUrl
    return Promise.resolve(dataUrl)
  }

  // 设置全屏
  public fullScreen() {
    const video = this.$el as any
    if (video.requestFullscreen) {
      video.requestFullscreen()
    } else if (video.mozRequestFullScreen) {
      video.mozRequestFullScreen()
    } else if (video.webkitRequestFullScreen) {
      video.webkitRequestFullScreen()
    }
  }

  // 退出全屏
  public exitFullscreen() {
    const video = this.$el as any
    if (video.exitFullscreen) {
      video.exitFullscreen()
    } else if (video.mozCancelFullScreen) {
      video.mozCancelFullScreen()
    } else if (video.webkitCancelFullScreen) {
      video.webkitCancelFullScreen()
    }
  }

  // 显示视频快照
  public showSnapshoot() {
    this._showSnapshoot = true
  }

  // 隐藏视频快照
  public hideSnapshoot() {
    this._showSnapshoot = false
  }

  constructor($container: HTMLDivElement, opts: any) {
    const $video = document.createElement('video')
    $video.setAttribute('src', opts.src)
    $container.appendChild($video)
    this.$el = $video
    this.addEventListeners()
  }
}

export class Video extends VideoBase {
  private _name: string = ''
  private _src: string = ''
  get name() {
    return this._name
  }

  get src() {
    return this._src
  }

  constructor($container: HTMLDivElement, opts: { name: string, src: string }) {
    super($container, opts)
    this._name = opts.name
    this._src = opts.src
  }
}
